#include "session_module.h"

#include "burst_module.h"
#include "login_module.h"
#include "protocol_client.h"
#include "repo.h"
#include "weilapb.h"
#include "weilapb_defines.h"
#include "wlsdk_define.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    wlsdk_message_callback callback;
} wl_session_global;

static wl_session_global s_session_global;

static wl_int32
    session_protocol_client_request_callback(PBWeilaMsg* message, void* content, wl_uint32 contentlen, void* context);
static wl_int32 session_message_callback(wl_int32 msgid, void* data, wl_uint32 datalen);

static void process_get_sessions(void* data, wl_int32 datalen);
static void process_attach_session(void* data, wl_int32 datalen);
static void process_check_attach_session(void* data, wl_int32 datalen);

static void session_sdk_message_callback(wl_uint32 msgid, wl_int32 resultcode, void* msgdata, wl_uint32 datalen) {
    if (s_session_global.callback) {
        s_session_global.callback(msgid, resultcode, msgdata, datalen);
    }
}

wl_int32 session_module_init(wlsdk_message_callback callback) {
    wl_int32  ret = 0;
    wl_module module;

    WLLOGI("session_module_init");
    memset(&module, 0, sizeof(wl_module));
    module.moduleid = WL_MODULE_SESSION;
    module.taskid   = WL_TASK_APP;
    module.callback = session_message_callback;
    ret             = wl_core_register_module(&module);
    if (0 != ret) {
        WLLOGW("wl_core_register_module session fail");
        return ret;
    }
    s_session_global.callback = callback;

    return ret;
}

wl_int32 session_module_end(void) {
    WLLOGI("session_module_end");
    wl_core_unregister_module(WL_MODULE_SESSION);
    s_session_global.callback = wl_null;
    return 0;
}

static wl_int32 session_message_callback(wl_int32 msgid, void* data, wl_uint32 datalen) {
    WLLOGD("msgid %d", msgid);
    switch (msgid) {
        case SESSION_MSG_GET_SESSIONS:
            process_get_sessions(data, datalen);
            break;
        case SESSION_MSG_ATTACH_SESSION:
            if (repo_get_extension_config_client_type() == REPO_CLIENT_EMBEDDED_ATTACH) {
                process_attach_session(data, datalen);
            }
            break;
        case SESSION_MSG_CHECK_ATTACH_SESSION:
            process_check_attach_session(data, datalen);
            break;
        case SESSION_MSG_TMP_SESSION_KEEPTIME: {
            wl_int32* duration = (wl_int32*)data;
            repo_set_tmp_session_keeptime(*duration);
            break;
        }
        default:
            WLLOGD("msgid %d not support", msgid);
            break;
    }
    return 0;
}

static wl_int32
    session_protocol_client_request_callback(PBWeilaMsg* message, void* content, wl_uint32 contentlen, void* context) {
    WLLOGD("message %d resultCode %d", message->message, message->resultCode);
    switch (message->message) {
        case WL_SESSION_EMBEDDED_ATTACH_MSG:
            if (WLSDK_RESULT_SUCCESS != message->resultCode) {
                wl_core_send_message(WL_MODULE_LOGIN, LOGIN_MSG_CLOSE_PROTOCOL_CLIENT, wl_null, 0);
            } else {
                if (content && sizeof(wl_uint64) == contentlen) {
                    wl_uint64 attach_sessionid = 0;
                    memcpy(&attach_sessionid, content, contentlen);
                    repo_set_attach_group_session(attach_sessionid);
                    wl_core_send_message(WL_MODULE_BURST, BURST_MSG_CHECK, wl_null, 0);
                }
            }
            break;
        default:
            break;
    }
    return 0;
}

static void process_get_sessions(void* data, wl_int32 datalen) {
    wl_list* session_list = repo_get_session_list();
    wl_int32 count        = wl_list_size(session_list);

    if (count > 0) {
        wl_uint32           sessions_size = sizeof(wlsdk_session_list) + sizeof(wlsdk_session) * count;
        wlsdk_session_list* sessions      = (wlsdk_session_list*)wl_malloc(sessions_size);
        wl_uint32           pos           = 0;
        if (sessions) {
            repo_session active_session;
            memset(sessions, 0, sessions_size);
            for (pos = 0; pos < count; pos++) {
                repo_session* session = (repo_session*)wl_list_get(session_list, pos);
                memcpy(&sessions->sessions[pos], &session->session, sizeof(wlsdk_session));
                sessions->sessions[pos].isdefault =
                    repo_is_session_default(session->session.sessionid, session->session.sessiontype);
            }
            if (0 == repo_get_active_session(&active_session)) {
                sessions->active_sessionid   = active_session.session.sessionid;
                sessions->active_sessiontype = active_session.session.sessiontype;
            }
            sessions->count = count;
            // sessions->attach_max = repo_get_extension_config_attach_limit();
            session_sdk_message_callback(WLSDK_MSG_SESSION_GET_SESSIONS, WLSDK_RESULT_SUCCESS, sessions, sessions_size);
            wl_free(sessions);
            return;
        }
    }
    session_sdk_message_callback(WLSDK_MSG_SESSION_GET_SESSIONS, WLSDK_RESULT_SUCCESS, wl_null, 0);
}

static void process_attach_session(void* data, wl_int32 datalen) {
    repo_session   session;
    wl_uint32      attach_count = 0;
    PBSessionInfo* attach_session =
        (PBSessionInfo*)wl_malloc(sizeof(PBSessionInfo) * repo_get_extension_config_attach_limit());
    if (wl_null == attach_session) {
        WLLOGW("malloc attach session fail");
        return;
    }
    if (0 != repo_get_default_session(&session)) {
        return;
    }
    attach_session[attach_count].sessionId   = session.session.sessionid;
    attach_session[attach_count].sessionType = session.session.sessiontype;
    attach_count                             = 1;
    WLLOGD("attach_count %d", attach_count);
    protocol_client_clear_request(WL_SESSION_EMBEDDED_ATTACH_MSG);
    if (attach_count) {
        PBEncResult enc_result = weilapb_buildEmbeddedAttachSession(attach_session, attach_count);
        wl_int32    resultcode = protocol_client_send_request(&enc_result,
                                                           &session.session.sessionid,
                                                           sizeof(session.session.sessionid),
                                                           PROTOCOL_CLIENT_REQUEST_TIMEOUT_60,
                                                           session_protocol_client_request_callback,
                                                           wl_null);
        if (0 > resultcode) {
            WLLOGW("protocol_client_send_request error");
            protocol_client_disconnect();
        }
    }
    wl_free(attach_session);
}

static void process_check_attach_session(void* data, wl_int32 datalen) {
    repo_session session;
    if (0 == repo_get_default_session(&session)) {
        if (!repo_is_attach_group_session(session.session.sessionid)) {
            wl_core_send_message(WL_MODULE_SESSION, SESSION_MSG_ATTACH_SESSION, wl_null, 0);
        }
    }
}

#ifdef __cplusplus
}
#endif
